package com.start.common.dic;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ReflectUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import com.start.common.dataImport.ExcelActionType;
import com.start.common.service.CommonDataDictService;
import com.start.common.tools.SpringContextTools;
import com.start.common.vo.CommonDataVo;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;


@EqualsAndHashCode(callSuper = true)
public class EntityDictMapperHandler extends BaseExcelMapperHandler<Object> {

    private final DictMapper dictMapper;

    private final Field field;

    private List<DictDataFormat> dataFormatList;

    public EntityDictMapperHandler(DictMapper dictMapper, Field field, ExcelActionType excelActionType) {
        super(excelActionType);
        this.field = field;
        this.field.setAccessible(true);
        this.dictMapper = dictMapper;
        setFormat(dictMapper.format());

        Class<?> fieldType = field.getType();
        setTypeName(fieldType.getTypeName());
        Class<? extends DictDataFormat>[] classes = dictMapper.formatHandler();

        if (excelActionType != ExcelActionType.EXCEl_TEMPLATE) {
            this.loadMapperData();
        }
        dataFormatList = new ArrayList<>();
        for (Class<? extends DictDataFormat> dictDataFormatClazz : classes) {
            DictDataFormat dictDataFormat = ReflectUtil.newInstance(dictDataFormatClazz);
            dataFormatList.add(dictDataFormat);
        }

    }

    public int getSort() {
        return dictMapper.sort();
    }

    public void loadMapperData() {
        if (loadStaticMapper()) return;
        loadDataTableMapper();
    }

    /**
     * 获取成员变量名称
     *
     * @return
     */
    @Override
    public String getFieldName() {
        return field.getName();
    }

    /**
     * 获取字段标题
     *
     * @return
     */
    @Override
    public String getTitle() {
        return dictMapper.value();
    }


    /**
     * 加载静态映射
     *
     * @return
     */
    private boolean loadStaticMapper() {
        if (dictMapper.mapperStatic().length() < 1) return false;
        List<CommonDataVo> tempArray = JSONArray.parseArray(dictMapper.mapperStatic(), CommonDataVo.class);
        if (tempArray.size() < 1) return false;
        if (excelActionType == ExcelActionType.EXCEL_IMPORT) {
            for (CommonDataVo commonDataVo : tempArray) {
                String temp = commonDataVo.getValue();
                commonDataVo.setValue(commonDataVo.getLabel());
                commonDataVo.setLabel(temp);
            }
        }
        initMapperData(tempArray);
        return true;
    }

    /**
     * 加载远程数据映射
     */
    private void loadDataTableMapper() {
        String table = dictMapper.mapperTable();
        if (StringUtils.isEmpty(table)) return;
        String label = dictMapper.mapperLabel();
        if (StringUtils.isEmpty(label)) return;
        String value = dictMapper.mapperValue();
        if (StringUtils.isEmpty(value)) return;
        String dataSource = dictMapper.mapperDataSource();
        String condition = dictMapper.tableCondition();
        if (StringUtils.isEmpty(condition)) condition = null;
        DynamicDataSourceProperties dynamicDataSourceProperties = SpringContextTools.getBean(DynamicDataSourceProperties.class);
        if (StringUtils.isEmpty(dataSource)) {
            dataSource = dynamicDataSourceProperties.getPrimary();
        }
        CommonDataDictService commonDataDictService = SpringContextTools.getBean(CommonDataDictService.class);
        if (excelActionType == ExcelActionType.EXCEL_IMPORT) {
            String temp = label;
            label = value;
            value = temp;
        }
        List<CommonDataVo> dataMapper = commonDataDictService.getDataMapper(dataSource, table, label, value, condition);
        initMapperData(dataMapper);
    }

    private void initMapperData(List<CommonDataVo> dataMapper) {
        this.setMapperTableData(dataMapper.stream().collect(Collectors.toMap(CommonDataVo::getValue, CommonDataVo::getLabel, (e1, e2) -> e2)));
    }

    /**
     * 获取导入参数
     *
     * @param originalValue
     * @return
     */
    @Override
    public Object getImportValue(String originalValue) {
        if (StringUtils.isEmpty(originalValue)) return null;
        Object fieldValue = null;
        String value = handlerMapper(originalValue);
        if (StringUtils.isEmpty(value)) return null;
        if (!dataFormatList.isEmpty()) {
            for (DictDataFormat format : dataFormatList) {
                fieldValue = format.onImportFormat(originalValue, value);
            }
            return fieldValue;
        }

        switch (getTypeName()) {
            case "java.lang.Long":
                fieldValue = Long.valueOf(value);
                break;
            case "java.lang.Integer":
                fieldValue = Integer.parseInt(value);
                break;
            case "java.lang.Short":
                fieldValue = Short.valueOf(value);
                break;
            case "java.lang.Double":
                fieldValue = Double.valueOf(value);
                break;
            case "java.lang.Float":
                fieldValue = Float.valueOf(value);
                break;
            case "java.lang.Boolean":
                fieldValue = Boolean.valueOf(value);
                break;
            case "java.lang.Byte":
                fieldValue = Byte.valueOf(value);
                break;
            case "java.lang.Character":
                fieldValue = value.charAt(0);
                break;
            case "java.util.Date":
            case "java.time.LocalTime":
                fieldValue = DateUtil.parse(value, getDateTimeFormatOrDefault());
                break;
            case "java.time.LocalDateTime":
                fieldValue = LocalDateTimeUtil.parse(value, getDateTimeFormatOrDefault());
                break;
            case "java.time.LocalDate":
                fieldValue = LocalDateTimeUtil.parseDate(value);
                break;
            case "java.math.BigDecimal":
                fieldValue = new BigDecimal(value);
                break;
            default:
                fieldValue = value;
                break;
        }


        return fieldValue;
    }

    /**
     * 获取导出参数
     *
     * @param entity
     * @return
     */
    @Override
    public String analysisExportValue(Object entity) {
        if (entity == null) return null;
        Object value = null;
        try {
            field.setAccessible(true);
            value = field.get(entity);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        if (value == null) return null;
        if (!dataFormatList.isEmpty()) {
            for (DictDataFormat format : dataFormatList) {
                value = format.onExportFormat(value);
            }
            return (String) value;
        }


        switch (getTypeName()) {
            case "java.lang.Long":
            case "java.lang.Integer":
            case "java.lang.Short":
            case "java.lang.Double":
            case "java.lang.Float":
            case "java.lang.Boolean":
            case "java.lang.Byte":
            case "java.lang.Character":
            case "java.lang.String":
                value = String.valueOf(value);
                break;
            case "java.math.BigDecimal":
                value = value.toString();
                break;
            case "java.util.Date":
            case "java.time.LocalTime":
                LocalTime localTime = (LocalTime) value;
                value = LocalDateTimeUtil.format(LocalDateTime.from(localTime), getDateTimeFormatOrDefault());
                break;
            case "java.time.LocalDateTime":
                LocalDateTime localDateTime = (LocalDateTime) value;
                value = LocalDateTimeUtil.format(localDateTime, getDateTimeFormatOrDefault());
                break;
            case "java.time.LocalDate":
                LocalDate localDate = (LocalDate) value;
                value = LocalDateTimeUtil.format(localDate, getDateTimeFormatOrDefault());
                break;
        }
        if (value == null) return null;
        return handlerMapper((String) value);
    }

    /**
     * 处理映射转换
     *
     * @param value
     * @return
     */
    protected String handlerMapper(String value) {
        if (value == null) return null;
        if (this.getMapperTableData() == null || this.getMapperTableData().size() < 1) return value;
        if (!dictMapper.multiple()) {
            return this.getMapperTableData().getOrDefault(value, value);
        }
        String s = dictMapper.multipleSplit();
        List<String> resultData = new ArrayList<>();
        String[] split = value.split(s);
        for (String item : split) {
            String v = this.getMapperTableData().getOrDefault(item, item);
            resultData.add(v);
        }
        return String.join(s, resultData);
    }

}
